package com.android.logcat;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import com.android.logcat.view.LoggerViewer;
import java.io.File;
import java.util.concurrent.Future;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import wei.mark.standout.StandOutWindow;

/**
 * @author GYL
 * @dateTime 2020/6/30-14:24
 * @description 日志配置文件
 */
public class LoggerConfig {
  
  private static volatile LoggerConfig instance;
  private Context mContext;
  private boolean enableDebug;
  private String tagPrefix;
  private boolean enableWriteFile;
  private String logFilePath;
  private ILogger loggerProxy;
  private Logger mLogger;
  private LoggerMonitor mLogFileWriteMonitor;
  private LoggerMonitor mLogViewMonitor;
  
  private ServiceConnection mServiceConnection;
  private LoggerAidl mLoggerAidl;
  
  private LoggerRunnable mLoggerThread;
  private ThreadPoolExecutor threadPoolExecutor;
  
  public synchronized static void setSingletonInstance(LoggerConfig.Builder builder) {
    if(instance==null){
      synchronized (LoggerConfig.class) {
        if (instance == null) {
          instance = new LoggerConfig(builder);
        }
      }
    }
  }
  
  public synchronized static LoggerConfig getInstance() {
    if (instance == null) {
      synchronized (LoggerConfig.class) {
        if (instance == null) {
          instance = new LoggerConfig(new Builder());
        }
      }
    }
    return instance;
  }
  
  private LoggerConfig(Builder builder) {
    if(builder.mContext.getApplicationContext()==null){
      mContext=builder.mContext;
    }else{
      mContext=builder.mContext.getApplicationContext();
    }
    enableDebug =builder.enableDebug;
    tagPrefix =builder.tagPrefix==null?"LOG":builder.tagPrefix;
    enableWriteFile=builder.enableWriteFile;
    logFilePath=builder.logFilePath==null?"":builder.logFilePath;
    loggerProxy =builder.logger;
    mLogFileWriteMonitor =builder.logFileInterceptor==null?new LoggerFileWrite(getContext(),logFilePath):builder.logFileInterceptor;
    mLogViewMonitor =builder.logViewInterceptor;
    //
    threadPoolExecutor = new ThreadPoolExecutor(0, 4, 3,
      TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new ThreadPoolExecutor.DiscardOldestPolicy());
    mLoggerThread=new LoggerRunnable(this);
    
    mLogger=new Logger(this);
  }
  
  public void setContext(Context context){
    this.mContext=context.getApplicationContext();
  }
  
  public Context getContext() {
    return mContext;
  }
  
  public boolean enableDebug() {
    return enableDebug;
  }
  
  public void setEnableDebug(boolean enableDebug){
    this.enableDebug=enableDebug;
  }
  
  public String getTagPrefix() {
    return tagPrefix;
  }
  
  public boolean isEnableWriteFile() {
    return enableWriteFile;
  }
  
  public String getLogFilePath() {
    return logFilePath;
  }
  
  public String getRawLogFile(){
    if(mLogFileWriteMonitor !=null && mLogViewMonitor instanceof LoggerFileWrite){
      File logFile = ((LoggerFileWrite) mLogViewMonitor).getLogFile();
      if(logFile!=null){
        return logFile.getAbsolutePath();
      }
    }
    return logFilePath;
  }
  
  public ILogger getLogger() {
    return mLogger;
  }
  
  /*public*/ ILogger getLoggerProxy(){
    return loggerProxy;
  }
  
  public LoggerMonitor getLogFileWriteMonitor(){
    return mLogFileWriteMonitor;
  }
  
  public LoggerMonitor getLogViewMonitor(){
    return mLogViewMonitor;
  }
  
  public void setLogViewMonitor(LoggerMonitor logViewMonitor){
    if(logViewMonitor !=null && !logViewMonitor.equals(this.mLogFileWriteMonitor)){
      this.mLogViewMonitor = logViewMonitor;
    }
    //关闭服务
    if(mServiceConnection!=null){
      mContext.unbindService(mServiceConnection);
      mServiceConnection=null;
      mLoggerAidl=null;
    }
  }
  
  /*public*/ LoggerRunnable loggerThread(){
    return mLoggerThread;
  }
  
  public void execRunnable(Runnable runnable){
    threadPoolExecutor.execute(runnable);
  }
  
  public Future<?> submitRunnable(Runnable runnable){
    Future<?> future = threadPoolExecutor.submit(runnable);
    return future;
  }
  
  public void shutdown(Runnable runnable){
    threadPoolExecutor.remove(runnable);
  }
  
  public void shutdown(){
    threadPoolExecutor.shutdown();
  }
  
  public Intent getShowStandOutWindowIntent(Class<? extends StandOutWindow> serviceClass){
   return StandOutWindow.getShowIntent(mContext, serviceClass, StandOutWindow.DEFAULT_ID);
  }
  
  public synchronized void bindLogWindowService(Intent serviceIntent) {
    if (null == mServiceConnection) {
      if(mLogViewMonitor ==null || !(mLogViewMonitor instanceof LoggerViewer)){
        this.mLogViewMonitor =new LoggerViewer();
      }
      mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
          mLoggerAidl = LoggerAidl.Stub.asInterface(service);
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
          mLoggerAidl=null;
        }
      };
      mContext.bindService(serviceIntent,mServiceConnection,Context.BIND_AUTO_CREATE);
    }
  }
  
  public LoggerAidl getLoggerAidl(){
    return mLoggerAidl;
  }
  
  public static class BindLoggerAidlStub extends LoggerAidl.Stub {
    private Handler mHandler;
    public BindLoggerAidlStub(Handler handler){
      mHandler=handler;
    }
    @Override
    public void addLogger(String loggerLevel, String loggerContent) throws RemoteException {
      Message message=Message.obtain();
      message.arg1=loggerLevel.charAt(0);
      message.obj=loggerContent;
      mHandler.sendMessage(message);
    }
  }
  
  public static final class Builder {
    
    private Context mContext;
    private boolean enableDebug;
    private String tagPrefix;
    private String logFilePath;
    private ILogger logger;
    
    private boolean enableWriteFile;
    private LoggerMonitor logFileInterceptor;
    private LoggerMonitor logViewInterceptor;
    
    private Builder() {
      enableDebug =true;
      tagPrefix ="";
      enableWriteFile=true;
      logFilePath="";
    }
  
    /**
     * @param context Application context
     * @return
     */
    public static Builder newBuilder(Context context) {
      Builder builder=new Builder();
      builder.mContext=context;
      return builder;
    }
    
    public Builder withEnableDebug(boolean enableDebug) {
      this.enableDebug = enableDebug;
      return this;
    }
    
    public Builder withTagPrefix(String tagPrefix) {
      this.tagPrefix = tagPrefix;
      return this;
    }
    
    public Builder withEnableWriteFile(boolean enableWriteFile) {
      this.enableWriteFile = enableWriteFile;
      return this;
    }
    
    public Builder withLogFilePath(String logFilePath) {
      this.logFilePath = logFilePath;
      return this;
    }
    
    public Builder withLogger(ILogger logger) {
      this.logger = logger;
      return this;
    }
    
    public Builder withLogFileInterceptor(LoggerMonitor interceptor){
      this.logFileInterceptor=interceptor;
      return this;
    }
  
    public Builder withLogViewInterceptor(LoggerMonitor interceptor){
      this.logViewInterceptor=interceptor;
      return this;
    }
  }
}